<?php


namespace app\im\handle\lib;


use app\im\handle\workManEvent;
use app\im\Router\checkRule;
use iflow\exception\Adapter\HttpResponseException;
use iflow\Middleware;
use iflow\swoole\implement\Server\WebSocket\WebSocket;

trait Handle
{
    public function checkRule(WebSocket|workManEvent $websocket, array $data)
    {
        try {
            $check = (new checkRule()) -> check($data['event'], $data['data']);
            // 验证失败返回404
            if ($check === false) {
                $websocket -> emit($data['event'], [
                    'code' => 404,
                    'msg' => '404 Not Found'
                ]);
            } else {
                // 获取控制器方法并执行
                [$controller, $method] = explode('@', $check);
                $refController = new \ReflectionClass($controller);

                if (!$refController -> hasMethod($method)) throw new \Exception('404 Not Found', 404);

                // 中间件验证通过
                if ($this -> triggerMiddleware($websocket, $data)) {
                    $controller = $refController -> newInstance($websocket);
                    // 执行控制器类注解
                    app() -> runAttributes($refController, $refController, $controller);
                    // 反射执行方法
                    app() -> invokeMethod(
                        [$controller, $method],
                        [$data['event'], $data['data']]
                    );
                }
            }
        } catch (\Throwable $exception) {
            $websocket -> emit($data['event'], [
                'code' => $exception -> getCode(),
                'msg' => $exception -> getMessage()
            ]);
        }
    }

    public function triggerMiddleware($websocket, array $data): bool
    {
        $app = app();
        try {
            return $app -> make(Middleware::class)
                -> initializer($app);
        } catch (HttpResponseException $exception) {
            $response = $exception -> getResponse();
            $websocket -> emit(
                $data['event'],
                $response -> data
            );
            return false;
        }
    }
}